package util

import (
	"fmt"
	"github.com/astaxie/beego"
	_ "github.com/astaxie/beego/cache"
	_ "github.com/astaxie/beego/cache/redis"
	"github.com/astaxie/beego/logs"
	"github.com/garyburd/redigo/redis"
	"os"
	"time"
)

var (
	redisPool *redis.Pool
)

func instance() *redis.Pool {

	if redisPool != nil {
		return redisPool
	}

	host := beego.AppConfig.String("Redis_HOST")
	logs.Info("RedisHost:", host)
	pass := beego.AppConfig.String("Redis_PASS")
	logs.Info("RedisPass:", pass)
	db, _ := beego.AppConfig.Int("Redis_DB")
	logs.Info("RedisDB:", db)
	if host == "" {
		panic("Redis Config not complete")
	}

	redisPool = &redis.Pool{
		MaxActive:   50,
		IdleTimeout: 300 * time.Second,
		Dial: func() (redis.Conn, error) {
			c, err := redis.Dial("tcp", host)
			if err != nil {
				return nil, err
			}
			if _, err := c.Do("AUTH", pass); err != nil {
				c.Close()
				return nil, err
			}
			if _, err := c.Do("SELECT", db); err != nil {
				c.Close()
				return nil, err
			}
			return c, nil
		},
	}
	conn := redisPool.Get()
	defer conn.Close()

	r, err := redis.String(conn.Do("PING", "test"))
	if err != nil {
		logs.Error("redis connection refused")
	}

	if r != "test" {
		logs.Info("redis connect failed")
		os.Exit(-1)
	} else {
		logs.Info("redis connect success")
	}

	return redisPool

}

func Exists(key string) bool {
	conn := instance().Get()
	defer conn.Close()
	if conn == nil {
		panic("redis init faild")
	}

	n, err := redis.Int(conn.Do("EXISTS", key))

	if err != nil {
		return false
	}
	return n > 0
}

/**
@param key
@param value
@param refresh true or false
@param ttl -1 means persistence
*/
func SetRedis(key string, value string, refresh bool, ttl int) bool {
	conn := instance().Get()
	defer conn.Close()

	exists := Exists(key)

	if exists && !refresh {
		return false
	}

	if refresh && exists {
		var err error

		if ttl != -1 {
			_, err = redis.String(conn.Do("set", key, value, "ex", ttl))
		} else {
			_, err = redis.String(conn.Do("set", key, value))
		}

		if err != nil {
			return false
		}

		return true
	}

	if !exists {
		var err error

		if ttl != -1 {
			_, err = redis.String(conn.Do("set", key, value, "ex", ttl))
		} else {
			_, err = redis.String(conn.Do("set", key, value))
		}

		if err != nil {
			return false
		}

		return true
	}

	return false
}

func GetRedis(key string) []byte {

	conn := instance().Get()
	defer conn.Close()

	val, err := conn.Do("get", key)
	if err != nil {
		return nil
	}
	if vall, ok := val.([]byte); ok {
		return vall
	}
	return []byte{}
}

func SetFirstList(key string, value string, ttl int) bool {
	conn := instance().Get()
	defer conn.Close()
	var err error
	if ttl != -1 {
		_, err = redis.String(conn.Do("lpush", key, value, "ex", ttl))
	} else {
		_, err = redis.String(conn.Do("lpush", key, value))
	}

	if err != nil {
		return false
	}

	return true
}

func SetList(key string, value string, ttl int) bool {
	conn := instance().Get()
	defer conn.Close()
	var err error
	if ttl != -1 {
		_, err = redis.String(conn.Do("rpush", key, value, "ex", ttl))
	} else {
		_, err = redis.String(conn.Do("rpush", key, value))
	}

	if err != nil {
		return false
	}

	return true
}
func GetList(key string) string {
	conn := instance().Get()
	defer conn.Close()
	val, err := redis.String(conn.Do("lpop", key))
	if err != nil {
		return ""
	}
	return val
	//if vall, ok := val; ok {
	//	return vall
	//}
	//
	//return ""
}

func GetLen(key string) *int {
	conn := instance().Get()
	defer conn.Close()
	val, err := conn.Do("llen", key)
	if err != nil {
		return nil
	}
	if vall, ok := val.(int); ok {
		return &vall
	}
	return nil
}

func SetMessage(messageID, message string) error {
	conn := instance().Get()
	defer conn.Close()

	_, err := conn.Do("set", fmt.Sprintf("message:%s", messageID), message, "EX", 60*60*24)
	if err != nil {
		logs.Error("redis: set message failed: ", err)
		return err
	}

	return nil
}

func GetMessage(messageID string) string {
	conn := instance().Get()
	defer conn.Close()

	res, err := redis.String(conn.Do("get", fmt.Sprintf("message:%s", messageID)))
	if err != nil {
		logs.Error("redis: set message failed: ", err)
		return ""
	}

	return res
}
